// fn adder(x: i32) -> fn(i32) -> i32 {
//     // mismatched types (expected fn pointer, found closure) [E0308]
//     |y| x + y

//     // expected identifier, found `(` (expected identifier)
//     // fn(y: i32) -> i32 {
//     //     x + y
//     // }
// }

fn adder(x: i32) -> impl Fn(i32) -> i32 {
    // x borrowed value does not live long enough
    // if move is missing
    move |y| x + y
    // if x < 4 {
    //     move |y| x + y
    // } else {
    //     move |y| x - y
    // }
}
fn adder2(x: i32) -> Box<dyn Fn(i32) -> i32> {
    if x < 4 {
        Box::new(move |y| x + y)
    } else {
        Box::new(move |y| x * y)
    }
}

#[test]
fn adder_test() {
    let add2 = adder(2);
    assert_eq!(5, add2(3));

    let add2 = adder2(2);
    assert_eq!(5, add2(3));

    let mul10 = adder2(10);
    assert_eq!(30, mul10(3));
}

// fn primes_up_to(n: usize) -> Vec<usize> {
//     let mut ans = Vec::with_capacity(n);

//     if n < 2 {
//         return ans;
//     }

//     ans.push(2);

//     // https://doc.rust-lang.org/1.22.0/book/first-edition/closures.html#closures-and-their-environment
//     // The closure needs ownership of vec to access elements
//     let is_prime = |n: usize| -> bool {
//         for x in ans {
//             if x * x > n {
//                 break;
//             }

//             if n % x == 0 {
//                 return false;
//             }
//         }

//         true
//     };

//     let mut i = 3;
//     while i <= n {
//         if is_prime(i) {
//             ans.push(i);
//         }

//         i += 2;
//     }

//     ans
// }
#[test]
fn move_test() {
    let mut s = String::from("hello");

    let f = |x| -> String {
        s.push(x);
        return s;
    };
    {
        println!("ret {:?}", f('a'));
        // note: closure cannot be invoked more than once because it moves the variable `s` out of its environment
        // println!("ret {:?}", f('a'));
    }
    // println!("ret {:?}", f('a'));
    //  borrowed here after move
    // println!("s {:?}", s);
}

#[test]
fn move_test2() {
    let num = 4;

    let f = |x: i32| x + num;
    println!("f(1) =  {:?}", f(1));

    println!("num {:?}", num);
}
